<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

class Css
{
    protected $_ci;
    protected $assetcachepath='';
    protected $assetcacheurl='';
    protected $cssurl='';
    protected $csspath='';
	protected $links=array();
	protected $relativeimageurl = '../siteimages/';
	protected $absoluteimageurl = '';
	protected $cacheassets='';
	protected $bundles;
	protected $php;
 
    function Css($config)
    {
        $this->__construct($config);
    }

    function __construct($config)
    {
        $this->_ci =&get_instance();
        $this->assetcachepath=$config['assetcachepath'];
       	$this->assetcacheurl=$config['assetcacheurl'];
      	$this->bundles=$config['bundles'];
	    $this->links=$config['links'];
        $this->cssurl=$config['cssurl'];
        $this->csspath=$config['csspath'];
	    $this->bundle=$config['bundle'];
	    $this->gzip=$config['gzip'];
	    $this->relativeimageurl =$config['relativeimageurl'];
	    $this->absoluteimageurl =$config['absoluteimageurl'];
	    if($this->assetcachepath=='') $this->assetcachepath=$this->_ci->site->paths->assetcache;
	    if($this->assetcacheurl=='') $this->assetcacheurl=$this->_ci->site->urls->assetcache;
	    if($this->cssurl=='') $this->cssurl=$this->_ci->site->urls->css;
	    if($this->csspath=='') $this->csspath=$this->_ci->site->paths->css;
	    if($this->absoluteimageurl=='') $this->absoluteimageurl=$this->_ci->site->urls->image;
	    if($this->bundle=='') $this->bundle=$this->_ci->site->bundle;
	    if($this->gzip=='') $this->gzip=$this->_ci->site->gzip;
	    $this->assetcachepath.='css/';
	    $this->assetcacheurl.='css/';
$this->php=<<<ENDPHP
<?php
	ob_start("ob_gzhandler");
	header("Content-type: text/css; charset: UTF-8");
	header("Cache-Control: must-revalidate");
	header("Content-Encoding: gzip");
	\$offset = 60 * 60 ;
	\$ExpStr = "Expires: ". gmdate("D, d M Y H:i:s",time() + \$offset) . " GMT";
	header(\$ExpStr);
?>

ENDPHP;
    }

 	function addlink($filename, $media='all')
	{
		foreach($this->links as $thislink)
		{
			if($thislink['link']==$filename && $thislink['media']==$media)
			{
				return;
			}
		}
		$this->links[]=array('link'=>$filename,'media'=>$media);
	}
	
	function compress($buffer) 
	{
		// remove comments
		$buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
		//remove unnecessary spaces and linefeeds
	    $buffer = str_replace(array("\r\n","\n\n","\r\r","\n\r"), "\n", $buffer);
	    $buffer = str_replace(array('     ','    ','   ','  '), ' ', $buffer);	      
	    $buffer = str_replace('{ ', '{', $buffer);
	    $buffer = str_replace(' }', '}', $buffer);
	    $buffer = str_replace('; ', ';', $buffer);
	    $buffer = str_replace(', ', ',', $buffer);
	    $buffer = str_replace(' {', '{', $buffer);
	    $buffer = str_replace('} ', '}', $buffer);
	    $buffer = str_replace(': ', ':', $buffer);
	    $buffer = str_replace(' ,', ',', $buffer);
	    $buffer = str_replace(' ;', ';', $buffer);
	    // replace relative urls with absolute urls
		$buffer = str_replace($this->relativeimageurl,$this->absoluteimageurl,$buffer);
		return $buffer;
	}
	
	function makelink($linkurl, $media)
	{
		return "\t\t<link href='{$linkurl}' media='{$media}' rel='stylesheet' type='text/css' />\n";
	}

	function getlinks()
	{
		$csslinks='';   // return value
		$linksprocessed=array(); // other files processed in bundles
		if(count($this->links) == 0)
		{
			// nothing to do
			return '';
		}
		// there are some links to process
		if($this->gzip!==TRUE && $this->bundle!==TRUE)
		{
			// not zipping, not bundling, just return each link individually
			foreach($this->links as $thislink)
			{
				$csslinks.= $this->makelink("{$this->cssurl}{$thislink['link']}.css",$thislink['media']);
			}
			return $csslinks;
		}
		// gzipping, bundling, or both... construct the cache filename and get the sourcefile timestamp 
		foreach($this->links as $thislink)
		{
			// default to the name of the link by itself
			$cachefilename=$thislink['link'];
			$alreadyprocessed=FALSE;
			foreach($linksprocessed as $thisprocessedlink)
			{
				if($thisprocessedlink['link'] == $thislink['link'] && $thisprocessedlink['media'] == $thislink['media'])
				{
					$alreadyprocessed=TRUE;
					break;
				}
			}
			if($alreadyprocessed)
			{
				// this link was processed in an earlier bundle
				continue;
			}
			$matchingbundle=FALSE;
			$latesttimestamp=0;
			if($this->bundle===TRUE)
			{
				// try to find a matching bundle
				foreach($this->bundles as $thisbundle)
				{
					foreach($thisbundle['links'] as $thisbundlefile)
					{
						// if any file in the bundle matches, then the bundle matches
						if($thisbundlefile==$thislink['link'] && $thislink['media']==$thisbundle['media'])
						{
							// found it!
							$matchingbundle=$thisbundle;
							break;
						}
					}
					if($matchingbundle!==FALSE) 
					{
						// found a bundle with this file... build the cache file name
						$cachefilename='';
						foreach($matchingbundle['links'] as $thisbundlefile)
						{
							$cachefilename.=$thisbundlefile;
						}
						// no need to continue trying to find another matching bundle
						break;
					}
				}
			}
			// cachefilename is set
			
			// check that the source file(s) exist(s) and get its (latest) timestamp
			if($matchingbundle!==FALSE)
			{
				// get the latest timestamp in the bundle
				foreach($matchingbundle['links'] as $thisbundlefile)
				{
					// the bundle needs to be rebuilt if any of its files have changed
					$fullpathtofile = "{$this->csspath}{$thisbundlefile}.css";
					if(!file_exists($fullpathtofile))
					{
						throw new Exception("Unable to load {$fullpathtofile}");
					}
					$whenfilechanged = filemtime($fullpathtofile);
					if($whenfilechanged > $latesttimestamp)
					{
						$latesttimestamp = $whenfilechanged;
					}
					// no need to process any of the rest of the files in the bundle
					$linksprocessed[]=array('link'=>$thisbundlefile,'media'=>$matchingbundle['media']);
				}
			}
			else
			{
				// no matching bundle, just get the timestamp for the css file
				$fullpathtofile = "{$this->csspath}{$thislink['link']}.css";
				if(!file_exists($fullpathtofile))
				{
					throw new Exception("Unable to load {$fullpathtofile}");
				}
				$latesttimestamp=filemtime($fullpathtofile);
			}
			
			$cachefilename= md5($cachefilename);
			if($this->gzip===TRUE)
			{
				// gzipped files have a php header and need to be processed
				$cachefilename.='.php';
			}
			else
			{
				// not gzipped files are straight css
				$cachefilename.='.css';
			}
			// check if the cache already exists
			$fullcachepath="{$this->assetcachepath}{$cachefilename}";
			if(file_exists($fullcachepath))
			{
				// get the timestamp on the cache
				$cachets = filemtime($fullcachepath);
				if($latesttimestamp <= $cachets)
				{
					// cache is good, use it
					$csslinks.= $this->makelink($this->assetcacheurl.$cachefilename, $matchingbundle['media']);
					// next link
					continue;
				}
				else
				{
					// cache is bad, delete it
					unlink($fullcachepath);
				}
			}
			// construct a cache
			if ( ! $fp = @fopen($fullcachepath, 'wb'))
			{
				throw new Exception("Unable to write cache file: {$fullcachepath}... check the premissions");
			}
			flock($fp, LOCK_EX);
			if($this->gzip===TRUE)
			{
				// add the php block at the beginning
				fwrite($fp, $this->php );
			}
			// append the css
			if($matchingbundle===FALSE)
			{
				// no matching bundle... just process the single file
				fwrite($fp,$this->compress(file_get_contents($fullpathtofile)));
				flock($fp, LOCK_UN);
				fclose($fp);
				// make it world read/writable
				@chmod($fullcachepath, 0777);
				$csslinks.= $this->makelink("{$this->assetcacheurl}{$cachefilename}",$thislink['media']);
				// next link
				continue;
			}
			// cache the whole bundle
			foreach($matchingbundle['links'] as $thisbundlefile)
			{
				// append each file in turn
				$fullpathtofile = "{$this->csspath}{$thisbundlefile}.css";
				fwrite($fp,$this->compress(file_get_contents($fullpathtofile)));
				fwrite($fp,"\n");
			}
			flock($fp, LOCK_UN);
			fclose($fp);
			// make it world read/writable
			@chmod($fullcachepath, 0777);
			$csslinks.= $this->makelink("{$this->assetcacheurl}{$cachefilename}",$matchingbundle['media']);
		}
	 	return $csslinks;
	}
} 
